"""--------------------------------------------------------------------------------------------------
Filename:   database.py
Author:     Chris Chester (christopher.chester@pg.canterbury.ac.nz) adapted from work done by Ben Han
Date:       04 September 2012
Description:
    Contains classes to process and store data for the biofeedback application.
--------------------------------------------------------------------------------------------------"""

from __future__ import with_statement   # to use the automatic file.close() functionality
import numpy as np
import wx, os, sys, traceback
import time
from config import ConfigData
import pickle


#===============================================================================
# CLASS: Patient
#    This class stores data for each patient. 
#    It is the top level object which contains all other data objects.
#    Must be stored as a native python object. The swig wrappers for the C++ 
#    wx code don't like to be pickled.
#===============================================================================
class Patient:
    def __init__(self, id=False, name='', dob='', gender='', notes='', sessions=[]):
        # Initial attributes
        if not id: 
            id = str(int(time.time()))  # Create an arbitrary unique ID if none provided.
            id = id[-8:]                # Uses the number of seconds since 00:00:00 1/1/1970
        self.id = id                        # patient ID number    
        self.name = name                    # patient name
        self.dob = dob                      # patient date of birth
        self.gender = gender                # patient gender
        self.notes = notes                  # storage for general notes, condition, treatment, etc
        self.session_record = sessions      # array containing references to the sessions completed by this patient
        temp = wx.DateTime.Now()
        self.date = temp.Format()           # date created, set to current time & date.
            # Format() returns a string in a format that can be parsed
            # back into a wx.DateTime object after unpickling.
        self.path = ""
        self.cfg = ConfigData()
    
    def __str__(self):
        s = 'ID:\t'+ str(self.id)+ '\n'+\
            'Name:\t'+ self.name+ '\n'+\
            'DoB:\t'+ self.dob+ '\n'+\
            'Gender:\t'+ self.gender+ '\n'+\
            'Date:\t'+ self.date+ '\n'+\
            'No. of sessions: '+ str(len(self.session_record))+ '\n'+\
            'Notes:\n'+ self.notes
        return s
        
    def add_session(self, session_rec):
        ''' Add a session to the internal record
            input - session record 
            output - total number of sessions'''
        
        self.session_record.append(session_rec)
        return len(self.session_record)
        
    def export(self, parent):
        ''' Opens up a directory selection dialog for user to choose location for output 
            input - frame for dialog to be placed
            output - path file will be placed'''
        # CSV files.
        patdir = self.path[:self.path.rfind('\\') + 1]
        dlg = wx.DirDialog(parent,
                           message="Choose a location for output files",
                           defaultPath=patdir)

        path = ""
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()    # directory name for output
            patfilename = self.path[self.path.rfind('\\')+1:self.path.rfind('.pat')]
            outdir = path + "\\" + patfilename + "_output"
            # Create a folder for output
            try:
                os.makedirs(outdir)
            except OSError:
                pass    # directory already exists
            except:
                sys.stderr.write(traceback.format_exc())
            else:
                path = outdir
            
            for i in range(len(self.session_record)):
                sr = self.session_record[i]
                j = self.path.rfind('\\')
                spath = self.path[:j+1] + sr.path
                try:
                    tempFile = open(spath, 'rb')
                    tempFile.flush()
                    s = pickle.load(tempFile)
                    tempFile.close()
                except:
                    msg = ">> Error loading session from file.\n"
                    sys.stderr.write(msg)
                    wx.MessageDialog(None, msg, "Session load error", wx.ICON_WARNING | wx.OK).ShowModal()
                    sys.stderr.write(traceback.format_exc())
                else:
                    outpath = path+ "\\"+ patfilename+ "_Sess"+ str(i+1).rjust(3,'0')
                    s.export(parent, outpath)
        return path
        


#===============================================================================
# CLASS: SessionRecord
#    Database object used to represent session objects in the patient object
#    Actual session objects should be saved in the same folder as the patient
#===============================================================================
class SessionRecord:
    def __init__(self, s_obj):
        ''' Constructor takes a database.Session object as its single argument '''
        self.date = s_obj.date
        self.sess_time = s_obj.sess_time
        self.stats = s_obj.stats
        self.path = ""    # path to the file containing the pickled session object
        

#===============================================================================
#  CLASS: Session
#     Stores the session information and configuration file used 
#===============================================================================
class Session:
    def __init__(self, config, pid,stats):
        self.timestamp = str(int(time.time()))
        temp = wx.DateTime.Now()
        self.date = temp.Format()           # time and date of session creation
                            # Date must be stored as a string here, as in Patient class (to be pickled)
        self.config = config                # ConfigData object used for the session
        self.patient = pid                  # ID of patient
        
        self.stats = stats
        # Initialise stats object
        
    def __str__(self):
        ''' Creates a string containing various session data
            output - string'''
        
        s = 'Patient ID,'+ str(self.patient)+ '\n'+\
            'Date,'+ self.date+ '\n'+\
            self.stats.get_col_labels()+ str(self.stats)
        return s
                
        
    def export(self, parent, filename=False):
        """ Write session to CSV files. Two files will be created: 
            1- Store stats for the session and each block. 
                It will also record the history of hits and misses. 
            2- The second file will store all the raw EMG data gathered 
                during the session.
            """
        if not filename:
            filename = 'ID_'+ str(self.patient)+ '_'+ self.timestamp
            file_choices = "Comma Seperated Values (*.csv)|*.csv"
            dlg = wx.FileDialog(
                parent,
                message="Export session data to CSV files",
                defaultDir=os.getcwd(),
                defaultFile=filename,
                wildcard=file_choices,
                style=wx.SAVE)
    
            if dlg.ShowModal() == wx.ID_OK:
                filename = dlg.GetPath()
            else:
                filename = ""       # cancelled
                return filename
                
        if filename[-4:] == '.csv':
            filename = filename[:-4]
        self.write_stats(filename)
        return filename
    
    def write_stats(self, filename):
        # write session statistics to a CSV file 
        name = filename+ '_stats.csv'
        csvfile = open(name, 'w')
        csvfile.write('<Output for session statistics>\n')
        csvfile.write('Patient ID,'+ str(self.patient)+ '\n')
        csvfile.write('Session date,'+ str(self.date)+ '\n')
        csvfile.write('PROTOCOLS:\n')
        csvfile.write('Delay,%s,length,%s\n' % (str(self.config.use_delay), str(self.config.DELAY_LEN)))
        csvfile.write(self.stats.get_col_labels())
        csvfile.write("\n")
        csvfile.write("\n")
        csvfile.flush()      # flush file buffer
        os.fsync(csvfile)
        csvfile.close()

# End of database.py
